<!-- //scroll-content为滚动区域， operation-btn为控制锚点行为的按钮。 -->
<template>
  <div class="anchor-point">
    <!-- 滚动区域 -->
    <div class="scroll-content" @scroll="onScroll">
      <div class="scroll-item" style="height: 500px; background: #3a8ee6">
        一层
      </div>
      <div class="scroll-item" style="height: 500px; background: red">二层</div>
      <div class="scroll-item" style="height: 500px; background: #42b983">
        三层
      </div>
      <div class="scroll-item" style="height: 1000px; background: yellow">
        四层
      </div>
    </div>
    <!-- 按钮 -->
    <div class="operation-btn">
      <div
        v-for="(item, index) in ['一层', '二层', '三层', '四层']"
        :key="index"
        @click="jump(index)"
        :style="{ background: activeStep === index ? '#eeeeee' : '#ffffff' }"
      >
        {{ item }}
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      activeStep: 0,
    };
  },
  methods: {
    //通过监听滚动事件，高亮显示锚点按钮
    //这里是通过遍历滚动项，判断滚动条滚动距离是否大于当前项的可滚动距离(即距离其offsetParent顶部的距离，这里是body)
    onScroll(e) {
      let scrollItems = document.querySelectorAll(".scroll-item");
      for (let i = scrollItems.length - 1; i >= 0; i--) {
        // 判断滚动条滚动距离是否大于当前滚动项可滚动距离
        let judge =
          e.target.scrollTop >=
          scrollItems[i].offsetTop - scrollItems[0].offsetTop;
        if (judge) {
          this.activeStep = i;
          break;
        }
      }
    },
    //添加点击事件，根据锚点滚动至对应区域并实现平滑滚动
    //这里参考网上的方法，将滚动距离细分为多个小段，并考虑向上及向下的的滚动，实现滚动的过渡动画。本来是打算使用scrollIntoView实现滚动动画，scrollIntoView在各个浏览器已经有很好的支持性，但是ScrollIntoViewOptions在浏览器的兼容性上还有问题，所以改用如下距离分割的方式。
    jump(index) {
      let target = document.querySelector(".scroll-content");
      let scrollItems = document.querySelectorAll(".scroll-item");
      // 判断滚动条是否滚动到底部
      if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
        this.activeStep = index;
      }
      let total = scrollItems[index].offsetTop - scrollItems[0].offsetTop + 10; // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
      let distance = document.querySelector(".scroll-content").scrollTop + 10; // 滚动条距离滚动区域顶部的距离
      // let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
      // 滚动动画实现, 使用setTimeout的递归实现平滑滚动，将距离细分为50小段，10ms滚动一次
      // 计算每一小段的距离
      let step = total / 50;
      if (total > distance) {
        smoothDown(document.querySelector(".scroll-content"));
      } else {
        let newTotal = distance - total;
        step = newTotal / 50;
        smoothUp(document.querySelector(".scroll-content"));
      }
      // 参数element为滚动区域
      function smoothDown(element) {
        if (distance < total) {
          distance += step;
          element.scrollTop = distance;
          setTimeout(smoothDown.bind(this, element), 10);
        } else {
          element.scrollTop = total;
        }
      }
      // 参数element为滚动区域
      function smoothUp(element) {
        if (distance > total) {
          distance -= step;
          element.scrollTop = distance;
          setTimeout(smoothUp.bind(this, element), 10);
        } else {
          element.scrollTop = total;
        }
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.anchor-point {
  flex-basis: 100%;
  width: 100vw;
  height: 100vh;
  display: flex;
  overflow: hidden;
  .scroll-content {
    height: 100%;
    width: 90%;
    overflow: scroll;
  }
  .operation-btn {
    width: 10%;
    height: 100%;
  }
}
</style>
